// CSE-102 DSA Assignment - Implementation of UserID-Password-Authentification using hash tables (Code 1).
// Ankit Mittal - 2010015

#include<stdio.h>
#include<string.h>

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int m=12;												//Number of slots in the hash table
char * filename = "users.txt";							//File containing authentication data
														//Each line in the file contains a username-
														//-its corresponding password seperated by a-
														//-white space of two tabs between them.


struct user{	int nil;
				char userid[30];
				char passcode[30];
           };

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int hash_dash(int key)									//Simple Modulo Function
{	int h = key%m;										//Division Method
	return h;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int hash(int key, int i)								//Linear Probing			
{	int h = (hash_dash(key) + i)%m;
	return h; 
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int generatekey(char * u)								//Generating key as the sum of ascii value of each character in the string
{	char c;
	int i=0,ascii=0;
	for(c=u[i];c!='\0';c=u[++i])
		{	ascii+=c;				
		}
	return(ascii);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void search_hash_table(struct user * table)				//Input a username, Obtain its password from the hash table, Input the password, Match
{	char password[30], username[30], input[30];
	int key, attempt=0;
	int i=0,j;
	struct user ptr;
	printf("\n\nEnter the User ID: ");
	scanf("%s",username);	
	key=generatekey(username);
	hashing:
	j=hash(key,i);
	ptr=table[j];
	if(table[j].nil)									//If the mapped slot is vacant
	{	printf("\nUser ID does not exist...\n");	
		search_hash_table(table);
		return;
	}
	else
	{	if(!strcmp(ptr.userid,username))				//If the username in the mapped slot matches our search
		{	strcpy(password,ptr.passcode);
		}
		else
		{	if(i==m)									//If username is not present in any slot
			{	printf("\nUser ID does not exist...\n");
				search_hash_table(table);
				return;
			}
			i++;
			goto hashing;
		}
	}	
	check:
	printf("\nEnter passcode: ");
	attempt++;
	scanf("%s",input);
	if(!strcmp(input,password))							//Comparing the actual password and the entered password
	{	printf("\nAuthentication Confirmed...");
		printf("\nThank You !!!\n\n");
	}
	else
	{	if(attempt!=3)
		{	printf("\nAuthentication Failed... Try Again...\nAttempts left: %d\n",3-attempt);
			goto check;
		}
		else
			printf("\nAuthentication failed... No attempts left...\n");
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void fill_hash_table(FILE * fp, struct user * table)	//Filling the hash table
{	
	char line[60], *p, *u;
	int n=0,i,j=0;
	int key;
	fp = fopen(filename, "r");
	if(fp==NULL)										//If file with this name does not exist
	{	printf("\nData not available...\n");
		exit(0);
	}
	while(1)
	{	fgets(line,60,fp);								//Reads one line at a time
		if(feof(fp)) break;								//If end of file has been reached
		n++;
		u=strtok(line,"\t\t");							//Identifying the username and password in-
		p=strtok(NULL,"\t\t\n");						//-line as they are seperated by 2 tabs
		key=generatekey(u);
		i=0;											//i is the probe index
		hashing:
		j=hash(key,i);									//j is the hash value obtained from the hash function
		if(n>m)
		{	printf("\nUsernames more than number of slots in the hash table...\nCannot hash with open addressing...\nProgram Terminated...");
			getchar();									//When entire table has been searched in vain for a blank slot
			exit(0);
		}
		if(table[j].nil)								//If the slot is vacant
		{	table[j].nil=0;
			strcpy(table[j].userid,u);
			strcpy(table[j].passcode,p);
		}
		else
		{	i++;
			goto hashing;
		}
		//printf("\n%s",table[j].userid);
		//printf(" %s",table[j].passcode);
	}
	fclose(fp);											//Terminating the file pointer
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int main()
{	int i;
	struct user table[m];
	FILE *fp;											//Declaring a file pointer
	for(i=0;i<m;i++)
	{	table[i].nil=1;
	}
	fill_hash_table(fp,table);
	search_hash_table(table);
	getchar();
	return 0;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
